iT邦幫忙

2026 iThome 鐵人賽

DAY 20
0
Software Development

從零打造邊緣運算閘道器:Raspberry Pi 與 Linux 底層軟硬整合實戰系列 第 20

Day 20 - 多執行緒的混亂:為何 Linux 內建的 CPU 排程器不適合用來控制 LED 燈號?

  • 分享至 

  • xImage
  •  

經過前幾天的奮戰,我們的 EdgeNode 已經具備了強大的檔案處理與 USB 通訊能力。它能在背景默默地攔截資料、切換磁碟、並用軟體模擬重插拔。

但是,對於第一線的醫療人員或使用者來說,他們根本看不到這些在 Linux 核心中翻騰的位元與指令。他們唯一能感知到這台無頭設備 (Headless Device) 當下狀態的途徑,只有機器外殼上的那顆 RGB LED 指示燈

  • 藍燈閃爍:資料傳輸中
  • 綠燈呼吸:待機中,準備就緒
  • 橘燈閃爍:同步錯誤
  • 紅燈恆亮:系統致命錯誤

聽起來很簡單對吧?只要在程式碼裡呼叫 GPIO.output() 就好了。但這正是災難的開始。

[問題情境] 當所有人都想發號施令

在一個具備一定複雜度的系統中,我們的 Python 應用程式往往是多執行緒 (Multi-threading) 的架構。

  • 有一個 SyncEngine 執行緒在監控 USB 的插拔。
  • 有一個 SerialWorker 執行緒在苦苦等待 UART 傳來的感測器資料。
  • 有一個主程式執行緒在監控系統整體的健康度。

當設備開機完成,主程式說:「亮綠燈呼吸」。
突然,UART 收到資料了,SerialWorker 說:「快!改閃藍燈」。
此時,底層的磁碟空間滿了,SyncEngine 說:「不對!亮紅燈警告!」

如果你只是單純在各個執行緒裡面寫:

def on_data_receive():
    # 藍燈閃爍
    while data_transferring:
        set_color(BLUE)
        time.sleep(0.5)
        set_color(BLACK)
        time.sleep(0.5)

[錯誤嘗試] 資源爭奪戰 (Race Condition)

當多個執行緒同時執行這類包含了 time.sleep() 的動畫迴圈,並且直接操作共享的硬體資源 (GPIO pin) 時,你會看到世界上最醜的燈號:混色閃爍

藍燈剛亮起,另一個執行緒把綠燈也點亮了,於是燈號變成了青色 (Cyan)。接著紅燈執行緒強行介入關閉了所有燈,LED 瘋狂地閃爍著不規則的雜訊。

[!WARNING]
這不僅僅是「難看」而已,在醫療或工業設備中,錯誤的燈號會導致嚴重的操作失誤。使用者可能以為資料已經傳輸完畢拔除設備,進而導致資料損毀。

為了解決這個問題,你可能會直覺地加上 Threading Lock (互斥鎖):

led_lock = threading.Lock()

def on_data_receive():
    with led_lock:
        while data_transferring:
            set_color(BLUE)
            time.sleep(0.5)
            set_color(BLACK)
            time.sleep(0.5)

這樣確實解決了混色的問題,但產生了另一個更致命的狀況:阻塞 (Blocking)
如果 data_transferring 持續了十分鐘,這十分鐘內 led_lock 都被死死扣住。如果這時系統發生了過熱或磁碟毀損的「致命錯誤」,紅燈警報根本亮不起來,因為它在等待 led_lock 釋放!

[底層原理] Linux 排程器的盲區

為什麼傳統的寫法會這麼痛苦?因為 Python 的 threading (或是說背後 Linux 作業系統的 CPU 排程器) 的設計宗旨在於 「公平地分配 CPU 時間給每一個執行緒」

排程器並不知道你的「紅燈」代表的是生死交關的致命錯誤,也不知道你的「綠燈」只是無關緊要的待機動畫。在作業系統眼中,它們只是兩段都需要被執行的程式碼。當你呼叫 time.sleep(0.5) 時,作業系統就開心地把 CPU 讓給其他執行緒去弄亂你的 GPIO。

[最終解決方案] 思維轉換

我們必須認知到:控制硬體狀態,不能依賴通用的 CPU 排程器,也不能直接在業務邏輯層呼叫硬體 API。

為了解決這場大亂鬥,我們需要將「發布指令」與「執行指令」徹底解耦。

  1. 其他執行緒不准碰 GPIO,它們只能「發送請求」。
  2. 系統中只能有一個唯一的工人 (Worker Thread) 有權力碰觸 LED 硬體。
  3. 這個工人必須內建一個「交通警察」,知道什麼訊號重要,什麼訊號可以被捨棄。

這就是我們明天要介紹的主題:軟即時架構 (Soft Real-Time) 與搶佔式任務排程。我們將親手用 Python 打造一個能秒殺上述所有問題的燈號控制引擎。敬請期待 Day 21!


上一篇
Day 19 - 軟體重插拔 (Software Re-plug):不碰硬體,用指令強制 Windows 重新掛載
下一篇
Day 21 - 軟即時架構 (Soft Real-Time):自己當交通警察,打造搶佔式任務排程
系列文
從零打造邊緣運算閘道器:Raspberry Pi 與 Linux 底層軟硬整合實戰26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言